import { Component, OnInit, Inject, OnDestroy } from "@angular/core";
import { LocaleService, TranslationService, Language } from "angular-l10n";
import big from "@assets/lib/big";

import {
  trigger,
  state,
  style,
  animate,
  transition
  // ...
} from "@angular/animations";

import {
  ISelectSymbolResponse,
  IMu,
  IZi,
  IQuerySymbol,
  IOnSymbol
} from "@/trade/store/models/trade";
import * as fromTrade from "@/trade/store/reducers/index";
import * as fromRoot from "@/reducers/index";
import { Store, select } from "@ngrx/store";
import { TradeActions } from "@/trade/store/actions";
import { map, filter } from "rxjs/operators";
import { Subscription, BehaviorSubject } from "rxjs";
import { ActivatedRoute } from "@angular/router";
import { Router, NavigationEnd } from "@angular/router";
import { takeUntil, mergeMap } from "rxjs/operators";
import { forkJoin, combineLatest } from "rxjs";
import { FormControl } from "@angular/forms";

interface IBuyItem {
  price: string;
  amount: string;
  total: string;
  percent: string;
}

interface ISellItem {
  price: string;
  amount: string;
  total: string;
  percent: string;
}

interface IPoint {
  label: string;
  val: string;
}

interface IOnDepth {
  type: string;
  item: IPoint;
}

@Component({
  selector: "app-panel-depth",
  templateUrl: "./panel-depth.component.html",
  styleUrls: ["./panel-depth.component.scss"],
  animations: [
    trigger("openClose", [
      // ...
      state(
        "open",
        style({
          opacity: 1
        })
      ),
      state(
        "closed",
        style({
          opacity: 0.5
        })
      ),
      transition("open => closed", [animate("1s")]),
      transition("closed => open", [animate("0.5s")])
    ])
  ]
})
export class PanelDepthComponent implements OnInit, OnDestroy {
  @Language() lang: string;

  isOpen = true;

  tv = {
    zi: {
      onFloat: 1,
      change: 0.2,
      lastPrice: "33.3333333"
    }
  };

  pointLists: Array<IPoint> = [
    {
      label: "5 decimals",
      val: "5"
    },
    {
      label: "4 decimals",
      val: "4"
    },
    {
      label: "3 decimals",
      val: "3"
    }
  ];

  onSymbol = {
    h: "0.0000",
    l: "0.0000",
    v: "0.0000",
    lastPrice: "0.0000",
    change: "0.00",
    symbol: "",
    sort: 0,
    isLove: false,
    type: "",
    mu: "",
    zi: ""
  };

  querySymbol: IQuerySymbol;

  symbolMap$ = this.store
    .pipe(select(fromRoot.symbolMap))
    .pipe(filter(symbolMap => !!symbolMap));

  onDepth: IOnDepth = {
    type: "",
    item: {
      label: "",
      val: ""
    }
  };

  sub$ = {
    queryAndConnected$: null,
    symbolMapSub$: null
  };

  depthSub$ = {
    buy$: null,
    sell$: null
  };

  point = 4;

  sellLists: Array<ISellItem> = [];
  buyLists: Array<IBuyItem> = [];

  constructor(
    @Inject("ConfigService") private configService,
    @Inject("UtilsService") private utilsService,
    @Inject("SkService") private skService,
    private store: Store<fromTrade.State>,
    private activatedRoute: ActivatedRoute
  ) {}
  toggle() {
    this.isOpen = !this.isOpen;
  }
  ngOnInit() {
    this.addListen();
  }

  mergePrice1(arr: Array<any>) {
    const h = {};
    arr.slice().forEach(d => {
      if (Object.prototype.toString.call(h[d.price]) !== "[object Array]") {
        h[d.price] = [];
      }
      h[d.price].push(d);
    });

    for (const key in h) {
      if (h.hasOwnProperty(key)) {
        const item = h[key];
        const b = item.slice().sort((pre, next) => {
          return Number(pre.amount) - Number(next.amount);
        });
        const min = b[0];
        const max = b[b.length - 1];

        h[max.price] = [max];
      }
    }
    const ret = [];
    for (const key in h) {
      if (h.hasOwnProperty(key)) {
        ret.push(h[key][0]);
      }
    }
    return ret;
  }

  mergePrice(arr: Array<any>, n: any) {
    const key = n[0];
    let a = arr.slice();
    if (big.isLt(n.amount, "0")) {
      n.amount = big.toFixed("0", this.configService.point);
    }
    let has = false;
    a.forEach((d, index) => {
      if (big.isEq(d.price, key.price)) {
        a[index].amount = key.amount;
        has = true;
      }
    });
    if (!has) {
      a = a.concat([key]);
    }
    return a;
  }

  addListen() {
    this.sub$.symbolMapSub$ = combineLatest(
      this.symbolMap$,
      this.activatedRoute.queryParams
    ).subscribe(([symbolMap, query]) => {
      const { symbol } = query;
      this.querySymbol = this.utilsService.splitQuerySymbol(symbol);
      const onSymbol =
        symbolMap[`${this.querySymbol.zi}${this.querySymbol.mu}`];
      if (!!onSymbol) {
        this.onSymbol = onSymbol;
      }
    });

    this.sub$.queryAndConnected$ = combineLatest(
      this.activatedRoute.queryParams,
      this.skService.connected$
    ).subscribe(([query, connected]) => {
      const [zi, mu] = query.symbol.split("_");
      if (connected) {
        this.utilsService.unsub(this.depthSub$);
        this.buyLists = [];
        this.sellLists = [];
        this.depthSub$.buy$ = this.skService
          .sub(`/topic/bid/${zi}_${mu}`)
          .subscribe(res => {
            let data = JSON.parse(JSON.parse(res.body).responseMessage);

            const isPush =
              Object.prototype.toString.call(data) === "[object Object]";

            if (isPush) {
              data = this.mergePrice(
                this.buyLists,
                this.utilsService.formatPoint([data])
              );
            } else {
              data = this.utilsService.formatPoint(data);
            }

            this.buyLists = this.utilsService.depth
              .formatBuy(data)
              .slice(0, 10)
              .sort((pre, next) => {
                return Number(
                  big.minus(
                    big.toFixed(next.price, this.configService.point),
                    big.toFixed(pre.price, this.configService.point)
                  )
                );
              });
          });
        this.depthSub$.sell$ = this.skService
          .sub(`/topic/ask/${zi}_${mu}`)
          .subscribe(res => {
            let data = JSON.parse(JSON.parse(res.body).responseMessage);

            const isPush =
              Object.prototype.toString.call(data) === "[object Object]";

            if (isPush) {
              data = this.mergePrice(
                this.sellLists,
                this.utilsService.formatPoint([data])
              );
            } else {
              data = this.utilsService.formatPoint(data);
            }

            this.sellLists = this.utilsService.depth
              .formatSell(data)
              .slice(0, 10)
              .sort((pre, next) => {
                return Number(
                  big.minus(
                    big.toFixed(pre.price, this.configService.point),
                    big.toFixed(next.price, this.configService.point)
                  )
                );
              });
          });
      }
    });
  }

  setBuy() {}

  setOnDepth(item, type) {
    this.toggle();
    this.onDepth.item = item;
    this.onDepth.type = type;
  }

  toggleShift() {}
  togglePoint() {}

  ngOnDestroy() {
    this.utilsService.unsub(this.sub$);
  }
}
